#!/usr/bin/env python

# gc1_viewer.py

from __future__ import division

import sys
import itertools

from Tkinter import *
import ttk

from ot_simulator.component import *
from ot_simulator.cutting_pass import cutting_pass
from ot_simulator.base_graph import base_graph
from ot_simulator.setup import setup
from ot_simulator.template.param_funs import param_ref, param_fun

class myframe(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.createWidgets()

class Application(myframe):
    def __init__(self, master=None):
        self.sr = slide_rest(angle = 90.0)
        self.tool_stack = (self.sr,)
        myframe.__init__(self, master)
        self.grid(sticky=N+S+E+W)

    def createWidgets(self):
        top=self.winfo_toplevel()
        top.rowconfigure(0, weight=1)
        top.columnconfigure(0, weight=1)
        for x in range(1, 4):
            self.rowconfigure(x, weight=1)
            self.columnconfigure(x, weight=1)
        self.left_side = left_side(self)
        self.left_side.grid(column=0, row=1, rowspan=3, sticky=N+S)
        self.top_side = top_side(self)
        self.top_side.grid(row=0, column=1, columnspan=3, sticky=E+W)
        self.simulator = {}
        for n, row, d_list in zip('357', range(1, 4), ('125', '137', '159')):
            for d, column in zip(d_list, range(1, 4)):
                sim = simulator(self, n, d, 'in')
                self.simulator[column, row] = sim
                sim.grid(column=column, row=row, sticky=N+S+E+W)

    def reset_ex_sr_ratio(self, ratio):
        ex = ratio
        sr = 1 - ratio
        self.sr.sr = sr
        for sim in self.simulator.itervalues():
            sim.reset_ex(ex)

class left_side(myframe):
    def createWidgets(self):
        pass

class top_side(myframe):
    def createWidgets(self):
        self.columnconfigure(0, weight=1)
        self.scale_var = DoubleVar()
        self.scale_var.set(0.5)
        self.scale = Scale(self, label="Ex/SR",
                                 from_=0.0, to=1.0, orient=HORIZONTAL,
                                 resolution=0.01, tickinterval=0.25,
                                 command=self.slide,
                                 variable=self.scale_var,
                          )
        self.scale.grid(sticky=E+W)
        self.last_value = None

    def slide(self, value):
        if value != self.last_value:
            print >> sys.stderr, "top_side.slide:", repr(value), \
                                 repr(self.last_value)
            self.last_value = value
            self.master.reset_ex_sr_ratio(float(value))

class simulator(myframe):
    def __init__(self, master, n=3, d=1, direction='in'):
        self.n = n
        self.d = d
        self.direction = direction
        myframe.__init__(self, master)

    def createWidgets(self):
        self.rowconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.controls = sim_controls(self, self.n, self.d, self.direction)
        self.controls.grid(row=0, column=0)
        self.canvas = Canvas(self, bg='#000', relief=SUNKEN)
        self.canvas.grid(row=0, column=1, sticky=N+S+E+W)
        self.canvas.bind('<Configure>', self.canvas_configure)
        self.gc = geometric_chuck(name='gc')
        self.setup = setup('bogus',
                           (headstock(), self.gc),
                           self.master.tool_stack,
                           (cutting_pass.step('index',
                              param_ref('index_inc'),
                              0.0,
                              param_fun(lambda n, d: 
                                num_headstock_rotations(((n, d),)) * 360.0,
                                'gc.n', 'gc.d')),
                            cutting_pass.generate(),
                           ),
                           full = dict(index_inc = 1.0),
                           quick = dict(index_inc = 10.0),
                          )
        self.dest_machine = graph(self.canvas)

    def canvas_configure(self, event):
        self.canvas.configure(height=event.height, width=event.width)
        #print >> sys.stderr, "canvas_configure (h w):", \
        #                     event.height, event.width, \
        #                     self.canvas.cget('height'), \
        #                     self.canvas.cget('width'), \
        #                     self.canvas.winfo_height(), \
        #                     self.canvas.winfo_width()

    def reset_ex(self, ex):
        self.gc.e = ex
        #print >> sys.stderr, "simulator.reset_ex:", ex
        self.redraw(True)

    def redraw(self, quiet = False):
        if hasattr(self, 'controls') and hasattr(self, 'canvas'):
            n, d, direction = self.controls.get()
            if not quiet:
                print >> sys.stderr, "simulator.redraw:", n, d, direction
            self.gc.n = n
            self.gc.d = d
            self.gc.direction = direction
            self.dest_machine.reset()
            self.setup.run('quick', self.dest_machine)
            self.dest_machine.draw()

class sim_controls(myframe):
    def __init__(self, master, n=3, d=1, direction='in'):
        self.n = n
        self.d = d
        self.direction = direction
        myframe.__init__(self, master)

    def createWidgets(self):
        self.n_label = Label(self, anchor=W, text="n")
        self.n_label.grid(row=0, column=0, sticky=W)
        self.n_var = StringVar()
        self.n_var.set(self.n)
        self.n_entry = myentry(self, self.master.redraw, width=2, justify=RIGHT,
                                     textvariable=self.n_var)
        self.n_entry.grid(row=0, column=1, sticky=W)
        self.d_label = Label(self, anchor=W, text="d")
        self.d_label.grid(row=1, column=0, sticky=W)
        self.d_var = StringVar()
        self.d_var.set(self.d)
        self.d_entry = myentry(self, self.master.redraw, width=2, justify=RIGHT,
                                     textvariable=self.d_var)
        self.d_entry.grid(row=1, column=1, sticky=W)
        self.direction_var = strvar(self.strvar_command)
        self.direction_var.set(self.direction)
        self.optionmenu = OptionMenu(self, self.direction_var, 'in', 'out')
        self.optionmenu.grid(row=2, column=0, columnspan=2, sticky=W)

    def strvar_command(self):
        print >> sys.stderr, "strvar_command called from OptionMenu"
        self.master.redraw()

    def get(self):
        n = self.n_entry.get_int()
        d = self.d_entry.get_int()
        direction = self.direction_var.get()
        return n, d, direction

class strvar(StringVar):
    def __init__(self, command=None):
        self.command = command
        StringVar.__init__(self)

    def set(self, value):
        StringVar.set(self, value)
        if self.command is not None:
            self.command()

class myentry(Entry):
    def __init__(self, master, command, **options):
        self.command = command
        Entry.__init__(self, master, **options)
        self.bind("<KeyPress-Return>", self.got_key)
        self.bind("<FocusOut>", self.got_key)

    def get_int(self):
        return int(self.get())

    def got_key(self, event):
        if not self.get().isdigit():
            print >> sys.stderr, "myentry event.type:", event.type, \
                                 "got illegal value:", repr(self.get())
            self.focus_force()
            self.bell()
        else:
            print >> sys.stderr, "myentry event.type:", event.type, \
                                 "got:", repr(self.get())
            self.command()

class graph(base_graph):
    def __init__(self, canvas):
        base_graph.__init__(self)
        self.canvas = canvas

    def get_width(self):
        return int(self.canvas.cget('width'))

    def get_height(self):
        return int(self.canvas.cget('height'))

    def reset(self):
        self.points = [('#ffffff', [])]

    def output_point(self, point, params):
        x, y, z = point.local_to_global()
        self.points[0][1].append((x, y))

    def draw(self):
        self.canvas.delete('figure')
        scale, max_x, max_y = self.calc_scale()
        self.canvas.create_line(
          fill=self.points[0][0],
          state=DISABLED,
          tags='figure',
          *tuple(itertools.chain.from_iterable(
                   self.scale_points(self.points[0][1], scale, max_x, max_y)))
        )


def run():
    global App
    App = Application()
    App.master.title("GC Viewer")
    App.mainloop()

if __name__ == "__main__":
    run()

